/* 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

Title : com.Angaliwa.Core
Author : Dave Jansen -- Zenitum
URL : http://www.zenitum.com/

Description : The Core of Angaliwa gives you certain
			  functionality that is used throughout the 
			  framework. Global variables, Loading external 
			  configuration files, etc. are part of this
			  module. Note that most Angaliwa modules assume
			  the core is loaded and in use.

History		: v1.5.090713 Re-wrote large parts of the module to
			  match Angaliwa 1.0b's new guidelines.
			  
			  v1.3.090603 Added the functionality to dynamically add
			  and preload Angaliwa modules and refer to other 
			  Angaliwa modules through the Core.
			  
			  v1.2.090602 Introducing loadXML(), the newer version of
			  loadConfiguration() that supports loading multiple
			  XML files (at once, even) and is smaller than it's
			  predecessor. Configuration variables are moved to
			  Core.c, and are categorized based on the XML's 
			  file name.
			  
			  v1.1.090525 Introducing Daisychains, which allows you to
			  integrate custom functions and (re)actions on
			  key moments in the code.
			  
			  v1.0.090512 Initial version. 

Created 	: May 12th, 2009

Version		: 1.5
Compatibility: 1.5

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
*/

package com.Angaliwa
{
	import flash.events.Event;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	
	public class Core
	{
		private static var variableHolder:Object = [];
        private static var xml:Object = [];
        
        /*
		 * Summary:      	Loads the specified XML file.
		 *					Originaly called loadConfiguration and
		 * 					loadConfigurationComplete, this package
		 * 					now supports loading an unlimited amount
		 *					of XML files.
		 * Return:       	Void
		 * Version:   	 	1.1
		 * Compatibility:	1.1
		 */
        public static function loadXML(file:String, alias:String=undefined, returnAction:Function=undefined, errorAction:Function=undefined):void{
        	var tmp:URLLoader = new URLLoader();
	    	Core.xml[tmp] = new Object();
	    	Core.xml[tmp].loader = tmp;
	    	Core.xml[tmp].file = file;
	    	Core.xml[tmp].returnAction = returnAction;
	    	Core.xml[tmp].loader.addEventListener(Event.COMPLETE, function(e:Event):void {
	    		if(Core.xml[e.target]){
	    			var nm:String = (alias) ? alias : file.split("/")[file.split("/").length-1].split(".")[0];
	    			var ref:Object = Core.xml[e.target];
	    			var input:XML = new XML(ref.loader.data);
	    			var output:Object = walkThroughXML(input.channel);
	    			
	    			/*
	    			for each(var n:XML in input.channel.children()){
	    				if(n.children().length() > 1){
	    					trace('TEST: '+n.name());
	    					for each (var sn:XML in n.children()){
	    						trace('   : '+sn.name()+', '+sn.valueOf());
	    					}
	    					
	    					trace(' ');
	    					//output[n.name()] = n;
	    				}
	    				else{
	    					trace('TEST: '+n.name()+', '+n.valueOf());
	    					output[n.name()] = n;
	    				}
	    			}
	    			*/
	    				    			
	    			Core.variableHolder[nm] = output;
	    			delete Core.xml[ref.loader];
	    			
	    			if(typeof (returnAction) == "function")
	    				ref.returnAction();
	    		}
	    	});
	    	
	    	if(typeof (errorAction) == "function"){
	    		// An error event action should be implemented, which will 
	    		// kick in when an XML file can't be loaded.
	    	}
	    	
			Core.xml[tmp].loader.load(new URLRequest(file));
        }
        
        public static function walkThroughXML(x:*):*{
        	var ret:Object = [];
        	
        	for each(var i:XML in x.children())
	        	if(i.children().length()>0)
	        		ret[i.name()] = walkThroughXML(i.valueOf());
	        	else return i.valueOf();
	        //ret[i.name()] = i.valueOf();
	        
        	return ret;
        }
		
		/*
		 * Summary:      	Either adds a new variable/object to the 
		 					variableHolder, or updates an already-
		 					existing one. Returns the added/updated
		 					object, which allows for code-chaining.
		 * Return:       	*
		 * Version:   	 	1.0
		 * Compatibility:	1.0
		 */
		public static function a(n:String, v:*):*{
			var t:Array = n.split(".");
			var crnt:* = Core.variableHolder;
			
			for(var i:int=0; i < t.length; i++){
				var tmp:String = t[i];
				if(!crnt.hasOwnProperty(tmp)){
					if(i < t.length-1){
						crnt[tmp] = new XML();
						crnt = crnt[tmp];
					} else{
						crnt[tmp] = v;
						
						// To make the newly created instance
						// aware of it's own name, let's give
						// it to him (if possible)
						if(v && v.hasOwnProperty("coreHandler"))
							v.coreHandler=tmp;
						
						return crnt[tmp];
					}
				} else crnt = crnt[tmp];
			}
			
			return false;
		}
		
		/*
		 * Summary:      	Checks if the requested variable exists, and
		 					if it does, returns it. Returns false when
		 					the variable does not exist.
		 * Return:       	*
		 * Version:   	 	1.0
		 * Compatibility:	1.0
		 */
		public static function g(n:String):*{
			var t:Array = n.split(".");
			var crnt:Object = Core.variableHolder;
			
			for(var i:int=0; i < t.length; i++){
				var tmp:String = t[i];
				if(crnt.hasOwnProperty(tmp)){
					crnt = crnt[tmp];
				}
				else{
					// TODO: Add debug integration later on.
					trace('ANGALIWA: It seems like '+n+' does not exist, got stuck at '+tmp+'.');
					return false;
				}
			}
			
			return crnt;
		}
		
		/*
		 * Summary:      	Removes (deletes) a variable/object from
		 					the variableHolder, if it exists. Returns
		 					true on successful deletion, or false when
		 					the variable did not exist to begin with.
		 * Return:       	Boolean
		 * Version:   	 	1.0
		 * Compatibility:	1.0
		 */
		public static function d(n:String):Boolean{
			var t:Array = n.split(".");
			var crnt:* = Core.variableHolder;
			
			for(var i:int=0; i < t.length; i++){
				var tmp:String = t[i];
				if(crnt.hasOwnProperty(tmp)){
					if(i < t.length-1){
						crnt = crnt[tmp];
					}
					else{
					  	delete crnt[tmp];
					  	return true;
					}
				}
			}
			
			return false;
		}
	}
}